package org.arch_learn.rpc.nz_rpc.endpoint;

import com.alibaba.fastjson.JSON;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.arch_learn.rpc.nz_rpc.common.RpcRequest;
import org.arch_learn.rpc.nz_rpc.common.RpcResponse;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationTargetException;

public class NettyRpcServer implements DisposableBean {
    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;

    public void startServer(String connectStr, ApplicationContext applicationContext) {
        String[] arr = connectStr.split(":");
        try {
            //1.创建线程组
            bossGroup = new NioEventLoopGroup(1);
            workerGroup = new NioEventLoopGroup();
            //2.创建服务端启动助手
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //3.设置启动参数
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //添加String的编解码器
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());
                            //添加业务处理类
                            pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                    //2.接收客户端请求，将传入字符串转换为RpcRequest对象
                                    System.out.println("================执行NettyRpcServerHandler.channelRead0()方法：收到消息" + msg);
                                    RpcRequest rpcRequest = JSON.parseObject(msg, RpcRequest.class);
                                    RpcResponse rpcResponse = new RpcResponse();
                                    rpcResponse.setResponseId(rpcRequest.getRequestId());
                                    try {
                                        Object result = handle(rpcRequest, applicationContext);
                                        rpcResponse.setResult(result);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        rpcResponse.setError(e.getMessage());
                                    }
                                    //6.给客户端进行响应
                                    String responseMsg = JSON.toJSON(rpcResponse) + "\n";
                                    //这里添加"\n"作为消息体的结束符，这样客户端的解码器在读到结束符之后，才会调用channelRead0()方法接收消息。
                                    System.out.println("================执行NettyRpcServerHandler.channelRead0()方法：返回消息" + responseMsg);
                                    channelHandlerContext.writeAndFlush(responseMsg);
                                }
                            });
                        }
                    });
            //4.绑定端口
            ChannelFuture channelFuture = serverBootstrap.bind(arr[0], Integer.valueOf(arr[1]));
            channelFuture.channel().closeFuture();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        finally {
//            if (bossGroup != null) {
//                bossGroup.shutdownGracefully();
//            }
//
//            if (workerGroup != null) {
//                workerGroup.shutdownGracefully();
//            }
//        }
    }

    private Object handle(RpcRequest rpcRequest, ApplicationContext applicationContext) throws InvocationTargetException, ClassNotFoundException {
        //3.根据传过来的beanName从缓存中查找对应的bean
        String className = rpcRequest.getClassName();
        Class<?> aClass = Class.forName(className);
        Object rpcServiceBean = applicationContext.getBean(aClass);
        if (null == rpcServiceBean) {
            throw new RuntimeException("根据bean类型：" + rpcRequest.getClassName() + "找不到rpc服务！");
        }

        //4.解析请求中的方法名称，参数类型，参数值
        Class<?> rpcServiceBeanClass = rpcServiceBean.getClass();
        String methodName = rpcRequest.getMethodName();
        Object[] parameters = rpcRequest.getParameters();
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();

        //5.通过反射调用bean的方法--CGlib反射调用
        FastClass fastClass = FastClass.create(rpcServiceBeanClass);
        FastMethod method = fastClass.getMethod(methodName, parameterTypes);
        Object result = method.invoke(rpcServiceBean, parameters);
        return result;
    }

    @Override
    public void destroy() throws Exception {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }

        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
    }
}
